"""
投资组合管理

提供投资组合创建、管理、分析等功能。
"""

from typing import Dict, List, Optional, Any, Callable
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from enum import Enum
import asyncio
from decimal import Decimal

# from ..data.models import MarketData  # 暂时注释，避免导入错误
from ..trading.order_manager import Order, OrderStatus, OrderType, OrderSide


class PortfolioType(Enum):
    """组合类型"""
    EQUITY = "equity"  # 股票组合
    BOND = "bond"  # 债券组合
    MIXED = "mixed"  # 混合组合
    COMMODITY = "commodity"  # 商品组合
    CURRENCY = "currency"  # 货币组合
    ALTERNATIVE = "alternative"  # 另类投资组合


class PortfolioStatus(Enum):
    """组合状态"""
    ACTIVE = "active"  # 活跃
    INACTIVE = "inactive"  # 非活跃
    SUSPENDED = "suspended"  # 暂停
    LIQUIDATING = "liquidating"  # 清算中
    CLOSED = "closed"  # 已关闭


@dataclass
class PortfolioHolding:
    """组合持仓"""
    symbol: str
    quantity: Decimal
    average_price: Decimal
    current_price: Decimal = Decimal('0')
    market_value: Decimal = Decimal('0')
    cost_basis: Decimal = Decimal('0')
    unrealized_pnl: Decimal = Decimal('0')
    realized_pnl: Decimal = Decimal('0')
    weight: float = 0.0  # 权重
    last_updated: datetime = field(default_factory=datetime.now)
    
    def __post_init__(self):
        """初始化后处理"""
        self.cost_basis = self.quantity * self.average_price
        self.update_market_value()
    
    def update_market_value(self) -> None:
        """更新市值"""
        self.market_value = self.quantity * self.current_price
        self.unrealized_pnl = self.market_value - self.cost_basis
        self.last_updated = datetime.now()
    
    def update_price(self, price: Decimal) -> None:
        """更新价格"""
        self.current_price = price
        self.update_market_value()


@dataclass
class PortfolioTransaction:
    """组合交易记录"""
    transaction_id: str
    symbol: str
    side: OrderSide
    quantity: Decimal
    price: Decimal
    amount: Decimal
    commission: Decimal = Decimal('0')
    timestamp: datetime = field(default_factory=datetime.now)
    order_id: Optional[str] = None
    notes: str = ""


@dataclass
class PortfolioSnapshot:
    """组合快照"""
    timestamp: datetime
    total_value: Decimal
    cash: Decimal
    holdings_value: Decimal
    total_pnl: Decimal
    unrealized_pnl: Decimal
    realized_pnl: Decimal
    holdings: Dict[str, PortfolioHolding]
    performance_metrics: Dict[str, float] = field(default_factory=dict)


class Portfolio:
    """
    投资组合
    
    管理单个投资组合的持仓、交易、绩效等。
    """
    
    def __init__(
        self,
        portfolio_id: str,
        name: str,
        portfolio_type: PortfolioType = PortfolioType.MIXED,
        initial_cash: Decimal = Decimal('1000000'),
        benchmark: Optional[str] = None
    ):
        """初始化投资组合"""
        self.portfolio_id = portfolio_id
        self.name = name
        self.portfolio_type = portfolio_type
        self.benchmark = benchmark
        self.status = PortfolioStatus.ACTIVE
        self.created_time = datetime.now()
        
        # 资金管理
        self.initial_cash = initial_cash
        self.cash = initial_cash
        self.total_value = initial_cash
        
        # 持仓管理
        self.holdings: Dict[str, PortfolioHolding] = {}
        self.transactions: List[PortfolioTransaction] = []
        
        # 绩效指标
        self.total_pnl = Decimal('0')
        self.unrealized_pnl = Decimal('0')
        self.realized_pnl = Decimal('0')
        
        # 历史快照
        self.snapshots: List[PortfolioSnapshot] = []
        
        # 回调函数
        self.on_transaction_callbacks: List[Callable] = []
        self.on_update_callbacks: List[Callable] = []
    
    def add_holding(self, symbol: str, quantity: Decimal, price: Decimal) -> None:
        """添加持仓"""
        if symbol in self.holdings:
            # 更新现有持仓
            holding = self.holdings[symbol]
            total_cost = holding.cost_basis + (quantity * price)
            total_quantity = holding.quantity + quantity
            
            if total_quantity > 0:
                holding.average_price = total_cost / total_quantity
                holding.quantity = total_quantity
                holding.cost_basis = total_cost
            else:
                # 持仓清零
                del self.holdings[symbol]
        else:
            # 新建持仓
            if quantity > 0:
                self.holdings[symbol] = PortfolioHolding(
                    symbol=symbol,
                    quantity=quantity,
                    average_price=price,
                    current_price=price
                )
        
        # 更新现金
        self.cash -= quantity * price
        self._update_portfolio_value()
    
    def remove_holding(self, symbol: str, quantity: Decimal, price: Decimal) -> Decimal:
        """减少持仓"""
        if symbol not in self.holdings:
            raise ValueError(f"持仓 {symbol} 不存在")
        
        holding = self.holdings[symbol]
        if quantity > holding.quantity:
            raise ValueError(f"减仓数量 {quantity} 超过持有数量 {holding.quantity}")
        
        # 计算已实现盈亏
        realized_pnl = (price - holding.average_price) * quantity
        self.realized_pnl += realized_pnl
        
        # 更新持仓
        holding.quantity -= quantity
        holding.cost_basis = holding.quantity * holding.average_price
        
        if holding.quantity == 0:
            del self.holdings[symbol]
        
        # 更新现金
        self.cash += quantity * price
        self._update_portfolio_value()
        
        return realized_pnl
    
    def update_prices(self, price_data: Dict[str, Decimal]) -> None:
        """更新价格数据"""
        for symbol, price in price_data.items():
            if symbol in self.holdings:
                self.holdings[symbol].update_price(price)
        
        self._update_portfolio_value()
        self._update_weights()
    
    def process_transaction(self, transaction: PortfolioTransaction) -> None:
        """处理交易"""
        if transaction.side == OrderSide.BUY:
            self.add_holding(transaction.symbol, transaction.quantity, transaction.price)
        else:
            realized_pnl = self.remove_holding(transaction.symbol, transaction.quantity, transaction.price)
            transaction.notes = f"已实现盈亏: {realized_pnl}"
        
        # 扣除手续费
        self.cash -= transaction.commission
        
        # 记录交易
        self.transactions.append(transaction)
        
        # 触发回调
        for callback in self.on_transaction_callbacks:
            try:
                callback(self, transaction)
            except Exception as e:
                print(f"交易回调执行失败: {e}")
    
    def get_holding(self, symbol: str) -> Optional[PortfolioHolding]:
        """获取持仓"""
        return self.holdings.get(symbol)
    
    def get_holdings_value(self) -> Decimal:
        """获取持仓总市值"""
        total = sum(holding.market_value for holding in self.holdings.values())
        return total if total else Decimal('0')
    
    def get_total_value(self) -> Decimal:
        """获取组合总价值"""
        return self.cash + self.get_holdings_value()
    
    def get_weight(self, symbol: str) -> float:
        """获取持仓权重"""
        if symbol not in self.holdings:
            return 0.0
        return self.holdings[symbol].weight
    
    def get_all_weights(self) -> Dict[str, float]:
        """获取所有持仓权重"""
        return {symbol: holding.weight for symbol, holding in self.holdings.items()}
    
    def create_snapshot(self) -> PortfolioSnapshot:
        """创建组合快照"""
        snapshot = PortfolioSnapshot(
            timestamp=datetime.now(),
            total_value=self.total_value,
            cash=self.cash,
            holdings_value=self.get_holdings_value(),
            total_pnl=self.total_pnl,
            unrealized_pnl=Decimal(str(self.unrealized_pnl)),
            realized_pnl=self.realized_pnl,
            holdings=self.holdings.copy()
        )
        
        self.snapshots.append(snapshot)
        return snapshot
    
    def get_performance_summary(self) -> Dict[str, Any]:
        """获取绩效摘要"""
        total_return = float((self.total_value - self.initial_cash) / self.initial_cash)
        
        return {
            'portfolio_id': self.portfolio_id,
            'name': self.name,
            'total_value': float(self.total_value),
            'cash': float(self.cash),
            'holdings_value': float(self.get_holdings_value()),
            'total_return': total_return,
            'total_pnl': float(self.total_pnl),
            'unrealized_pnl': float(self.unrealized_pnl),
            'realized_pnl': float(self.realized_pnl),
            'holdings_count': len(self.holdings),
            'transactions_count': len(self.transactions),
            'status': self.status.value,
            'created_time': self.created_time.isoformat()
        }
    
    def _update_portfolio_value(self) -> None:
        """更新组合价值"""
        holdings_value = self.get_holdings_value()
        self.total_value = self.cash + holdings_value
        
        # 更新未实现盈亏
        self.unrealized_pnl = sum(holding.unrealized_pnl for holding in self.holdings.values())
        
        # 更新总盈亏
        self.total_pnl = self.unrealized_pnl + self.realized_pnl
        
        # 触发更新回调
        for callback in self.on_update_callbacks:
            try:
                callback(self)
            except Exception as e:
                print(f"更新回调执行失败: {e}")
    
    def _update_weights(self) -> None:
        """更新持仓权重"""
        total_value = self.get_holdings_value()
        if total_value > 0:
            for holding in self.holdings.values():
                holding.weight = float(holding.market_value / total_value)
        else:
            for holding in self.holdings.values():
                holding.weight = 0.0


class PortfolioManager:
    """
    投资组合管理器
    
    管理多个投资组合，提供统一的接口。
    """
    
    def __init__(self):
        """初始化组合管理器"""
        self.portfolios: Dict[str, Portfolio] = {}
        self.active_portfolio_id: Optional[str] = None
        
        # 回调函数
        self.on_portfolio_created_callbacks: List[Callable] = []
        self.on_portfolio_updated_callbacks: List[Callable] = []
    
    def create_portfolio(
        self,
        portfolio_id: str,
        name: str,
        portfolio_type: PortfolioType = PortfolioType.MIXED,
        initial_cash: Decimal = Decimal('1000000'),
        benchmark: Optional[str] = None
    ) -> Portfolio:
        """创建投资组合"""
        if portfolio_id in self.portfolios:
            raise ValueError(f"组合 {portfolio_id} 已存在")
        
        portfolio = Portfolio(
            portfolio_id=portfolio_id,
            name=name,
            portfolio_type=portfolio_type,
            initial_cash=initial_cash,
            benchmark=benchmark
        )
        
        self.portfolios[portfolio_id] = portfolio
        
        # 如果是第一个组合，设为活跃组合
        if self.active_portfolio_id is None:
            self.active_portfolio_id = portfolio_id
        
        # 触发回调
        for callback in self.on_portfolio_created_callbacks:
            try:
                callback(portfolio)
            except Exception as e:
                print(f"组合创建回调执行失败: {e}")
        
        return portfolio
    
    def get_portfolio(self, portfolio_id: str) -> Optional[Portfolio]:
        """获取投资组合"""
        return self.portfolios.get(portfolio_id)
    
    def get_active_portfolio(self) -> Optional[Portfolio]:
        """获取活跃组合"""
        if self.active_portfolio_id:
            return self.portfolios.get(self.active_portfolio_id)
        return None
    
    def set_active_portfolio(self, portfolio_id: str) -> None:
        """设置活跃组合"""
        if portfolio_id not in self.portfolios:
            raise ValueError(f"组合 {portfolio_id} 不存在")
        self.active_portfolio_id = portfolio_id
    
    def list_portfolios(self) -> List[Portfolio]:
        """列出所有组合"""
        return list(self.portfolios.values())
    
    def update_all_prices(self, price_data: Dict[str, Decimal]) -> None:
        """更新所有组合的价格"""
        for portfolio in self.portfolios.values():
            portfolio.update_prices(price_data)
            
            # 触发更新回调
            for callback in self.on_portfolio_updated_callbacks:
                try:
                    callback(portfolio)
                except Exception as e:
                    print(f"组合更新回调执行失败: {e}")
    
    def get_total_value(self) -> Decimal:
        """获取所有组合总价值"""
        total = sum(portfolio.get_total_value() for portfolio in self.portfolios.values())
        return total if total else Decimal('0')
    
    def get_summary(self) -> Dict[str, Any]:
        """获取管理器摘要"""
        total_value = self.get_total_value()
        
        return {
            'total_portfolios': len(self.portfolios),
            'active_portfolio_id': self.active_portfolio_id,
            'total_value': float(total_value),
            'portfolios': [portfolio.get_performance_summary() for portfolio in self.portfolios.values()]
        }
    
    def process_order_fill(self, portfolio_id: str, order: Order, fill_price: Decimal, fill_quantity: Decimal) -> None:
        """处理订单成交"""
        portfolio = self.get_portfolio(portfolio_id)
        if not portfolio:
            raise ValueError(f"组合 {portfolio_id} 不存在")
        
        # 创建交易记录
        transaction = PortfolioTransaction(
            transaction_id=f"{order.order_id}_{datetime.now().timestamp()}",
            symbol=order.symbol,
            side=order.side,
            quantity=fill_quantity,
            price=fill_price,
            amount=fill_price * fill_quantity,
            order_id=order.order_id
        )
        
        # 处理交易
        portfolio.process_transaction(transaction)
    
    def add_portfolio_callback(self, event_type: str, callback: Callable) -> None:
        """添加组合回调"""
        if event_type == "created":
            self.on_portfolio_created_callbacks.append(callback)
        elif event_type == "updated":
            self.on_portfolio_updated_callbacks.append(callback)
        else:
            raise ValueError(f"不支持的事件类型: {event_type}")